﻿using System;
using System.Collections.Generic;
using System.Text;

namespace SuperX.Common.Collection
{
    // 
    public class ConcurrentList<T>
    {
        public ConcurrentList()
        {
            this._syncRoot = new object();
            this._list = new List<T>();
        }

        public T this[int index]
        {
            get
            {
                object syncRoot = this._syncRoot;
                lock (syncRoot)
                {
                    if (index < 0 || index >= this._list.Count)
                    {
                        return default(T);
                    }
                    return this._list[index];
                }
            }
        }

        public int Count
        {
            get
            {
                int count;
                lock (this._syncRoot)
                {
                    count = this._list.Count;
                }
                return count;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        public void Add(T item)
        {
            object syncRoot = this._syncRoot;
            lock (syncRoot)
            {
                this._list.Add(item);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <param name="item"></param>
        public void Insert(int index, T item)
        {
            lock (_syncRoot)
            {
                this._list.Insert(index, item);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="items"></param>
        public void AddRange(IEnumerable<T> items)
        {
            lock (_syncRoot)
            {
                this._list.AddRange(items);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T GetAt(int index)
        {
            lock (_syncRoot)
            {
                if (this._list.Count <= 0 || index >= this._list.Count)
                {
                    return default(T);
                }
                return this._list[index];
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T GetAndRemoveAt(int index)
        {
            T result;
            lock (_syncRoot)
            {
                if (this._list.Count <= 0 || index >= this._list.Count)
                {
                    result = default(T);
                }
                else
                {
                    T t = this._list[index];
                    this._list.RemoveAt(index);
                    result = t;
                }
            }
            return result;
        }

        // 
        public void RemoveAt(int index)
        {
            object syncRoot = this._syncRoot;
            lock (syncRoot)
            {
                if (this._list.Count > 0 && index < this._list.Count)
                {
                    this._list.RemoveAt(index);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        public void Remove(T item)
        {
            lock (_syncRoot)
            {
                if (this._list.Count > 0)
                {
                    this._list.Remove(item);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <param name="array"></param>
        /// <param name="arrayIndex"></param>
        /// <param name="count"></param>
        public void CopyTo(int index, T[] array, int arrayIndex, int count)
        {
            object syncRoot = this._syncRoot;
            lock (syncRoot)
            {
                if (this._list.Count > 0 && index + count <= this._list.Count)
                {
                    this._list.CopyTo(index, array, arrayIndex, count);
                }
            }
        }

        // 
        public T[] GetAndRemoveRange(int index, int count)
        {
            T[] result;
            lock (_syncRoot)
            {
                if (this._list.Count <= 0 || index + count > this._list.Count)
                {
                    result = null;
                }
                else
                {
                    T[] array = new T[count];
                    this._list.CopyTo(index, array, 0, count);
                    this._list.RemoveRange(index, count);
                    result = array;
                }
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <param name="count"></param>
        public void RemoveRange(int index, int count)
        {
            lock (_syncRoot)
            {
                if (this._list.Count > 0 && index + count <= this._list.Count)
                {
                    this._list.RemoveRange(index, count);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public T Find(Predicate<T> match)
        {
            object syncRoot = this._syncRoot;
            T result;
            lock (syncRoot)
            {
                result = ((this._list.Count <= 0) ? default(T) : this._list.Find(match));
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public List<T> FindAll(Predicate<T> match)
        {
            List<T> result;
            lock (_syncRoot)
            {
                result = ((this._list.Count <= 0) ? null : this._list.FindAll(match));
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <param name="count"></param>
        /// <param name="item"></param>
        /// <param name="comparer"></param>
        /// <returns></returns>
        public int BinarySearch(int index, int count, T item, IComparer<T> comparer)
        {
            int result;
            lock (_syncRoot)
            {
                if (index < 0 || index + count > this._list.Count)
                {
                    result = -1;
                }
                else
                {
                    result = this._list.BinarySearch(index, count, item, comparer);
                }
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="match"></param>
        public void RemoveAll(Predicate<T> match)
        {
            lock (_syncRoot)
            {
                if (this._list.Count > 0)
                {
                    this._list.RemoveAll(match);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public void Clear()
        {
            object syncRoot = this._syncRoot;
            lock (syncRoot)
            {
                if (this._list.Count > 0)
                {
                    this._list.Clear();
                }
            }
        }

        private readonly List<T> _list;
        private readonly object _syncRoot;
    }
}
